import pandas as pd
import numpy as np
import geopandas as gpd
import json
import statsmodels
import plotly
import plotly.express as px
import plotly.io as pio
# pio.renderers.default='jupyter'
# pio.renderers.default='jupyterlab'
# allow full interactivity offlice
plotly.offline.init_notebook_mode()
Load Data¶
Giffords Gun Law Scorecard¶
Load the Giffords Gun Law Scorecard for each state. Note, original scores have been coerced into a 5-point Likert scale and a numeric grade has also been assigned to each letter grades.
scorecard_df = pd.read_csv('giffords_gun_law_scorecard.csv')
scorecard_df.head(n=10)
| state_abbrev | giffords_grade | grade | |
|---|---|---|---|
| 0 | NY | A | 4.0 |
| 1 | NJ | A | 4.0 |
| 2 | MD | A | 4.0 |
| 3 | MA | A | 4.0 |
| 4 | IL | A | 4.0 |
| 5 | HI | A | 4.0 |
| 6 | CT | A | 4.0 |
| 7 | CA | A | 4.0 |
| 8 | WA | B | 3.0 |
| 9 | VA | B | 3.0 |
Firearm Related Deaths¶
Load the firearm related mortality data for each state from the CDC. Data was acquired using the Socrate API and wrangled for this presentation. See DataWrangling.ipynb for details.
firearm_related_deaths_df = pd.read_csv('tidy-489q-934x-firearm-related-injury.csv')
firearm_related_deaths_df.tail(n=10)
| year_and_quarter | state | state_abbrev | mortality_per_100k | |
|---|---|---|---|---|
| 540 | 2022 Q3 | South Dakota | SD | 16.7 |
| 541 | 2022 Q3 | Tennessee | TN | 21.6 |
| 542 | 2022 Q3 | Texas | TX | 16.1 |
| 543 | 2022 Q3 | Utah | UT | 12.4 |
| 544 | 2022 Q3 | Vermont | VT | 13.4 |
| 545 | 2022 Q3 | Virginia | VA | 15.3 |
| 546 | 2022 Q3 | Washington | WA | 13.0 |
| 547 | 2022 Q3 | West Virginia | WV | 17.9 |
| 548 | 2022 Q3 | Wisconsin | WI | 14.5 |
| 549 | 2022 Q3 | Wyoming | WY | 23.6 |
Make state, state abbreviation, and Giffords grade columns categorical.
firearm_related_deaths_df = firearm_related_deaths_df.astype({'state': 'category', 'state_abbrev': 'category'})
print(firearm_related_deaths_df.dtypes)
scorecard_df = scorecard_df.astype({'state_abbrev': 'category', 'giffords_grade' : 'category'})
print(scorecard_df.dtypes)
year_and_quarter object state category state_abbrev category mortality_per_100k float64 dtype: object state_abbrev category giffords_grade category grade float64 dtype: object
Retain only the latest data for firearm related deaths.
deaths_q3_2022 = firearm_related_deaths_df[firearm_related_deaths_df['year_and_quarter'] == '2022 Q3']
deaths_q3_2022.head()
| year_and_quarter | state | state_abbrev | mortality_per_100k | |
|---|---|---|---|---|
| 500 | 2022 Q3 | Alabama | AL | 25.6 |
| 501 | 2022 Q3 | Alaska | AK | 23.3 |
| 502 | 2022 Q3 | Arizona | AZ | 20.9 |
| 503 | 2022 Q3 | Arkansas | AR | 22.4 |
| 504 | 2022 Q3 | California | CA | 9.1 |
Merge firearm related deaths and Giffords scrore datasets.
df = deaths_q3_2022.merge(scorecard_df, on='state_abbrev')
df = df.sort_values(by=['giffords_grade'], ascending=True)
df = df.reset_index(drop=True)
df.head()
| year_and_quarter | state | state_abbrev | mortality_per_100k | giffords_grade | grade | |
|---|---|---|---|---|---|---|
| 0 | 2022 Q3 | Illinois | IL | 14.7 | A | 4.0 |
| 1 | 2022 Q3 | Maryland | MD | 13.5 | A | 4.0 |
| 2 | 2022 Q3 | New Jersey | NJ | 5.3 | A | 4.0 |
| 3 | 2022 Q3 | Hawaii | HI | 4.3 | A | 4.0 |
| 4 | 2022 Q3 | Massachusetts | MA | 3.9 | A | 4.0 |
Choropleth map of Firearm Mortality¶
us_states = json.load(open('states.geojson', 'r'))
Add a new property 'id' to features - 'id' is the default name of column that is used to map values from the dataset ('state') to the corresponding State in GerJSON data.
for feat in us_states['features']:
feat['id'] = feat['properties']['NAME']
Display Firearm Mortality by State on map.
fig = px.choropleth(df, locations='state', scope='usa', geojson=us_states,
color='mortality_per_100k',
hover_name='state',
hover_data=['giffords_grade'],
color_continuous_scale='Portland',
color_continuous_midpoint=np.average(df['mortality_per_100k']),
labels={
"mortality_per_100k": "Firearm Mortality per 100,000 persons",
"giffords_grade" : "Giffords Gun Law Scorecard",
"state" : "State"
},
title='Firearm Mortality and Gun Law Scorecard by State (Hover over map for details)')
fig.show()
Heatmap (Treemap) of Firearm Mortality grouped by Giffords Gun Law Scorecard¶
The Heatmap makes revels the following trends:
- States with the strictest gun laws have the lowest firearm related mortality rates
- There are a few outliers: e.g. New Mexico, which has extremely high firearm related mortality despite a non-failing gun law score. Utah, Maine, Iowa, and New Hampshire are other outliers. Explaining outliers is not in scope for this presentation
import numpy as np
fig = px.treemap(df, path=[px.Constant('Giffords Gun Law Scorecard'), 'giffords_grade', 'state_abbrev'], values='mortality_per_100k',
color='mortality_per_100k',
# labels={"mortality_per_100k": "Firearm Mortality per 100,000 persons"},
labels={
"mortality_per_100k": "Firearm Mortality per 100,000 persons",
"state" : "State",
"grade" : 'Giffords Gun Law Scorecard',
"giffords_grade" : 'Giffords Gun Law Scorecard'
},
height=600,
width=1000,
title='Trend: States with <b>Stronger</b> Firearm Control Laws have <b>Lower</b> Firearm Mortality<br>(Hover over treemap for details)</br>',
#hover_name='label',
# hover_data=['mortality_per_100k'],
color_continuous_scale='Portland',
color_continuous_midpoint=np.average(df['mortality_per_100k'])
)
fig.show()
Scatterplot with trend line using Ordinary Least Squares¶
fig = px.scatter(df, x="grade", y="mortality_per_100k",
color="mortality_per_100k",
labels={
"mortality_per_100k": "Firearm Mortality per 100,000 persons",
"state" : "State",
"grade" : 'Giffords Gun Law Scorecard',
"giffords_grade" : 'Giffords Gun Law Scorecard'
},
hover_name='state',
hover_data=['giffords_grade', 'mortality_per_100k'],
color_continuous_scale=px.colors.diverging.Portland,
color_continuous_midpoint=15,
height=600,
width=1000,
trendline='ols',
title='Trend: States with <b>Stronger</b> Firearm Control Laws have <b>Lower</b> Firearm Mortality<br>(Hover over points for details)</br>'
)
fig.update_xaxes(type='category')
fig.update_xaxes(tickmode='array', tickvals=df['grade'], ticktext=df['giffords_grade'])
fig.update_layout(
xaxis_title='Giffords Gun Law Scorecard for States',
yaxis_title="Mortality per 100,000 persons"
)
#fig.update_traces(visible=False, selector=dict(mode="markers"))
fig.show()